﻿using System.Collections.Generic;
using System.IO;

namespace Red.CommUtils
{
    public class ProtoReaderBinary : comm.IProtoReader
    {
        private BinaryReader _buffer;
        private Stack<long> _scopedSizeCounterStack;

        public ProtoReaderBinary( Stream stream )
        {
            _buffer = new BinaryReader( stream );
            _scopedSizeCounterStack = new Stack<long>();
        }

        public comm.EMessageID PeekTypeHash()
        {
            long currentPosition = _buffer.BaseStream.Position;
            comm.EMessageID result = (comm.EMessageID)_buffer.ReadUInt32();
            _buffer.BaseStream.Seek( currentPosition, SeekOrigin.Begin );
            return result;
        }

        public void Error( string txt, params object[] args )
        {

        }

        public bool ReadFloat( out float outResult )
        {
            outResult = _buffer.ReadSingle();
            return true;
        }

        public bool ReadDouble( out double outResult )
        {
            outResult = _buffer.ReadDouble();
            return true;
        }

        public bool ReadUint8( out byte outResult )
        {
            outResult = _buffer.ReadByte();
            return true;
        }

        public bool ReadUint16( out ushort outResult )
        {
            outResult = _buffer.ReadUInt16();
            return true;
        }

        public bool ReadUint32( out uint outResult )
        {
            outResult = _buffer.ReadUInt32();
            return true;
        }

        public bool ReadUint64( out ulong outResult )
        {
            outResult = _buffer.ReadUInt64();
            return true;
        }

        public bool ReadInt8( out sbyte outResult )
        {
            outResult = _buffer.ReadSByte();
            return true;
        }

        public bool ReadInt16( out short outResult )
        {
            outResult = _buffer.ReadInt16();
            return true;
        }

        public bool ReadInt32( out int outResult )
        {
            outResult = _buffer.ReadInt32();
            return true;
        }

        public bool ReadInt64( out long outResult )
        {
            outResult = _buffer.ReadInt64();
            return true;
        }

        public bool ReadBool( out bool outResult )
        {
            outResult = _buffer.ReadBoolean();
            return true;
        }

        public bool ReadString( out string outResult )
        {
            ushort length;
            if ( !ReadUint16( out length ) )
            {
                outResult = null;
                return false;
            }

            char[] data = _buffer.ReadChars( length );
            outResult = new string( data );
            
            return true;
        }

        public void PushScopedSizeCounter()
        {
            uint size = _buffer.ReadUInt32();
            long endPosition = _buffer.BaseStream.Position;
            endPosition += size;
            _scopedSizeCounterStack.Push( endPosition );
        }

        public void PopScopedSizeCounter()
        {
            long endPosition = _scopedSizeCounterStack.Pop();
            _buffer.BaseStream.Seek( endPosition, SeekOrigin.Begin );
        }

        public bool BeginObject( string typeName, uint typeHash )
        {
            typeHash = _buffer.ReadUInt32();
            PushScopedSizeCounter();
            return true;
        }

        public void EndObject()
        {
            PopScopedSizeCounter();
        }

        public uint StartPropsBlock()
        {
            uint count = 0;
            count = _buffer.ReadUInt32();
            return count;
        }

        public bool BeginProperty( out uint outNameHash )
        {
            outNameHash = _buffer.ReadUInt32();
            PushScopedSizeCounter();
            return true;
        }

        public void EndProperty()
        {
            PopScopedSizeCounter();
        }

        public int BeginArray()
        {
            uint elementTypeHash = _buffer.ReadUInt32();
            PushScopedSizeCounter();
            int count = _buffer.ReadInt32();
            return count;
        }

        public void EndArray()
        {
            PopScopedSizeCounter();
        }
    }
}
